package oceanlife.psychmodel;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Random;

import oceanlife.Agent;
import oceanlife.OLSet;
import oceanlife.RandomGen;
import oceanlife.pathfinding.Pnt;


public class PsychComp {
	private Ocean ocean = new Ocean();
	private Agent thisAgent;
	
	private Random rand = new Random(0);
	private double mindChangeExpConstante = 0.99;//chance that possibility for "mind change" = 1-divconst^x
	
	//Behaviour
	private double selfControl;
	private double passiveEndurance;
	private double emotionalRegulation;
	
	//Emotion regulation
	private double compassionMean;
	private double hopeMean;
	private double anxietyMean;
	private double fearMean;
	
	//Emotions
	private double compassion;
	private double hope;
	private double anxiety;
	private double fear;
	
	//total agents inside influence range
	private double totalEncounterCounter = 0;

	//[0] = indication how long it has been since a change of mind
	//[1] = 1 or 0 indication of what last decision was.
	private HashMap<Integer,Integer[]> dontCare = new HashMap<Integer,Integer[]>();
	private double dontCareCounter = 0;
	private HashMap<Integer,Integer[]> keepDistance = new HashMap<Integer,Integer[]>();
	private double keepDistanceCounter = 0;
	
	//if route is recalculated
	private boolean altRoute = false;
	
	public PsychComp(Agent thisAg){
		thisAgent = thisAg;
		
		selfControl = ocean.initSelfControl();
		passiveEndurance = ocean.initPassiveEndurance();
		emotionalRegulation = ocean.initEmotionalRegulation();
		
		compassionMean = ocean.initCompassionReg();
		hopeMean = ocean.initHopeReg();
		anxietyMean = ocean.initAnxietyReg();
		fearMean = ocean.initFearReg();
		
		compassion = 0;//RandomGen.getGaussian();
		hope = 0;//RandomGen.getGaussian();
		anxiety = 0;//RandomGen.getGaussian();
		fear = 0;//RandomGen.getGaussian();
	}
	
	public boolean dontCare(Integer i){
		if(dontCare.get(i) != null && dontCare.get(i)[1] == 1){
			return true;
		} else {
			return false;
		}
	}
	
	public boolean keepDistance(Integer i){
		if(keepDistance.get(i) != null && keepDistance.get(i)[1] == 1){
			return true;
		} else {
			return false;
		}
	}
	
	public void updateEmotions(ArrayList<Agent> agents) {
		//4 emotions that will be changed during emoUpdate
		//compassion, hope, anxiety, fear
		double[] emoMod = new double[4];
		Arrays.fill(emoMod, 1.0);
		
		situationModification(agents,emoMod);
		attentionalDeployment(agents,emoMod);
		cognativeChange(emoMod);
		responseModulation(emoMod);
		
		//compassion = ocean.initCompassion();
		//hope = ocean.initHope();
		//anxiety = ocean.initAnxiety();
		//fear = ocean.initFear();
		double fearChangeSteapness = 0.1;
		fear -= (fearChangeSteapness*(emoMod[3]-fearMean)*(emoMod[3]-fearMean)*(emoMod[3]-fearMean))/OLSet.getCps();
		
		countersReset();
	}

	private void situationModification(ArrayList<Agent> agents, double[] emoMod) {		
		for(Agent ag : agents){
			if(ag.getPosition().distanceTo(thisAgent.getPosition()) < 2.0*thisAgent.getDs()){
				totalEncounterCounter++;
				changeBehaviourKeepDistance(ag);//compassion
				changeBehaviourDontCare(ag);//fear, anxiety, compassion
				changeBehaviourAltRoute();//fear, anxiety, hope
				changeBehaviourPushy();//hope
			}
		}
		emoMod[3] += dontCareCounter-(totalEncounterCounter/2.0);
		//System.out.println(emoMod[3]+" "+dontCareCounter+"/"+totalEncounterCounter);
	}

	//compassion
	private void changeBehaviourKeepDistance(Agent ag) {
		// TODO Auto-generated method stub
		
	}

	//fear, anxiety, compassion
	private void changeBehaviourDontCare(Agent ag) {
		Double dontCareModAttempt = rand.nextDouble();
		Integer[] lastDontCareMod = dontCare.get(ag.hashCode());
		if(lastDontCareMod == null){
			lastDontCareMod = new Integer[]{Integer.MAX_VALUE,0};
		} else if(lastDontCareMod[1] == 1){
			dontCareCounter++;
		}
		if(dontCareModAttempt < (1-Math.pow(mindChangeExpConstante,lastDontCareMod[0]))){
			double fearAttempt = rand.nextDouble();
			if(fearAttempt < fear){
				if(lastDontCareMod[1] != 1){
					dontCareCounter++;
				}
				lastDontCareMod[0] = 0;
				lastDontCareMod[1] = 1;
			} else {
				if(lastDontCareMod[1] != 0){
					dontCareCounter--;
				}
				lastDontCareMod[0] = 0;
				lastDontCareMod[1] = 0;
			}
		} else {
			lastDontCareMod[0]++;
		}
		dontCare.put(ag.hashCode(),lastDontCareMod);		
	}

	//fear, anxiety, hope
	private void changeBehaviourAltRoute() {
		// TODO Auto-generated method stub
		
	}

	//hope
	private void changeBehaviourPushy() {
		// TODO Auto-generated method stub
		
	}


	private void attentionalDeployment(ArrayList<Agent> agents, double[] emoMod) {
		for(Agent ag : agents){
			if(ag.getPosition().distanceTo(thisAgent.getPosition()) < 2.0*thisAgent.getDs()){
				activeCopingOn(ag);
			}			
		}
		
	}

	private void cognativeChange(double[] emoMod) {
		// TODO Auto-generated method stub
		
	}

	private void responseModulation(double[] emoMod) {
		// TODO Auto-generated method stub
		
	}

	private void countersReset() {
		totalEncounterCounter = 0;		
		dontCareCounter = 0;
		keepDistanceCounter = 0;
		altRoute = false;
	}

	public void activeCopingOn(Agent ag) {
		

		
		//
		/*Double keepDistanceModAttempt = rand.nextDouble();
		Integer[] lastKeepDistanceMod = keepDistance.get(ag.hashCode());
		if(lastKeepDistanceMod == null){
			lastKeepDistanceMod = new Integer[]{Integer.MAX_VALUE,0};
		} else if (lastKeepDistanceMod[1] == 1){
			keepDistanceCounter++;
		}
		if(keepDistanceModAttempt < (1-Math.pow(divConstante,lastKeepDistanceMod[0]))){
			double fearAttempt = rand.nextDouble();
			if(fearAttempt < fear){
				if(lastKeepDistanceMod[1] != 1){
					keepDistanceCounter++;
				}
				lastKeepDistanceMod[0] = 0;
				lastKeepDistanceMod[1] = 1;
			} else {
				lastKeepDistanceMod[0] = 0;
				lastKeepDistanceMod[1] = 0;
				keepDistanceCounter--;
			}
		} else {
			lastKeepDistanceMod[0]++;
		}
		keepDistance.put(ag.hashCode(),lastKeepDistanceMod);*/

		
		//return partialFDynamic;
	}
	
	public double fear(){
		return fear;
	}

}
